const path = require('path');
const glob = require('glob');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');   //打包HTML插件
const CopyWebpackPlugin = require('copy-webpack-plugin');   //复制文件插件
const CleanWebpackPlugin = require('clean-webpack-plugin'); //打包之前清理历史目标文件插件
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');    //在html中引入其他静态资源文件
const ExtractTextPlugin = require('extract-text-webpack-plugin');       //分离css插件
const Es3ifyPlugin = require('es3ify-webpack-plugin');      //解决IE8 缺少标识符问题 的插件

//获取某个目录下的所有匹配的文件
//{filename:[filepath]}
const fileResolve = (filepath) => {
    let files = glob.sync(filepath),
        fileMap = {},basename, extname;
    files.forEach((file, i) => {
        extname = path.extname(file);
        basename = path.basename(file, extname);
        fileMap[basename] = [path.join(__dirname, file)];
    });
    return fileMap;
}

//环境信息
const ENV = {
    __TEST__: process.env.ENV === 'TEST' ? true : false,        //测试环境
    __DEV__: process.env.ENV === 'DEV' ? true : false,          //开发环境
    __PRERELEASE__: process.env.ENV === 'PRO' ? true : false,   //生产环境
    __CONTEXT__: (process.env.context || '').trim(),            //项目上文路径
    'process.env': {
        NODE_ENV: process.env.ENV === 'DEV' ? JSON.stringify('production') : JSON.stringify('development')
    }
}

const PORT = 3001,                      //端口
    DIST = 'dist',                      //打包后的目录
    commonChunkName = 'commons',        //公共的代码的名称
    publicPath = `${ENV.__CONTEXT__}`,  //公共的访问路径，此处是ES6的写法
    devtool = ENV.__DEV__ ? 'cheap-module-eval-source-map' : false,
    favicon = './src/assets/images/favicon.ico',        //favicon.ico
    viewTemplate='./src/view-template/template.html';  //html模板文件

//获取所有的入口文件
let entries = fileResolve('./src/page/**.js');
//添加首页,需要特殊处理
entries['index'] = [path.join(__dirname, './src/index.js')];
//babel-polyfill 防止IE8出现Object.defineProperty错误
Object.keys(entries).forEach((k,i)=>{
    //babel-polyfill es6-promise
    entries[k].splice(0,0,'babel-polyfill','es6-promise');
});

const config = {
    entry: entries,
    output: {
        path: path.join(__dirname, DIST),
        filename: 'assets/js/[name].[chunkhash].js',
        publicPath: publicPath
    },
    module: {
        rules: [{
                test: /\.js(x)*$/,
                loader: 'babel-loader?cacheDirectory',
                exclude: /node_modules/,    //排除编译的目录，可以加快编译速度
                include: [path.join(__dirname, 'src')]
            },
            {
                test: /\.css$/,
                use: ExtractTextPlugin.extract({    //使用ExtractTextPlugin分离css
                    fallback: 'style-loader',
                    use: {
                        loader: 'css-loader',
                        options: {
                            modules: false
                        }
                    }
                })
            },
            {
                test: /\.(woff|woff2|ttf|svg|eot)(\?v=\d+\.\d+\.\d+)?$/,
                use: 'url-loader?limit=10240&name=assets/fonts/[name].[ext]'
            },
            {
                test: /\.(png|jpg|gif|jpeg)$/,
                use: 'file-loader?limit=10240&name=assets/images/[name].[ext]'
            }
        ]
    },

    resolve: {
        //设置之后再import或require的时候可以省略后缀
        extensions: ['.js', '.jsx', '.json', '.css', '.png', '.jpg', '.jpeg', '.gif'],
        //搜索目录，可以加快搜索的速度
        modules: [
            path.resolve(__dirname, 'src'),
            path.resolve(__dirname, 'node_modules')
        ],
        //给组件取别名，简化import或require,可以将自己写的组件在引入的时候能够像其他组件一样
        alias: {},
    },
    externals: {},
    context: __dirname,
    devtool: devtool,
    devServer: {
        contentBase: path.join(__dirname, DIST),
        compress: true, //启用gzip压缩
        port: PORT,
        inline: true,
        clientLogLevel: 'warning',
        historyApiFallback: true,   //防止404
    },
    plugins: [
        new Es3ifyPlugin(),                 //IE8 处理标识符无效错误
        new webpack.DefinePlugin(ENV),      //环境信息
        new webpack.NoEmitOnErrorsPlugin(), //出错后不退出
        new CleanWebpackPlugin([`${DIST}/*`]),
        new HtmlWebpackPlugin({             //首页特殊处理
            title: '首页',
            id:'index',
            filename: './index.html',       //存放打包后的html文件，此处相对于DIST目录
            template: viewTemplate,         //html模板文件
            minify: {                       //压缩HTML文件
                minimize: false,            //压缩
                removeComments: false,      //移除HTML中的注释
                collapseWhitespace: false   //删除空白符与换行符
            },
            favicon: favicon || '',
            chunks: [commonChunkName, 'index'], //需要引入那些模块
            hash: false
        }),
        new ExtractTextPlugin({ //抽出css文件
            filename: 'assets/css/[name].[hash].css',
            allChunks: true
        }),
        new webpack.optimize.CommonsChunkPlugin({ //提取公共的文件[css/js均会提取]
            name: commonChunkName,
            filename: 'assets/js/commons.[hash].js',
            minChunks: 2,
        }),
        new webpack.DllReferencePlugin({ //DLL插件加速编译
            context: __dirname,
            name: 'vendor',
            //在这里引入 manifest 文件
            manifest: require('./src/json/vendor-manifest.json')
        })

    ]
}

//如果是生产环境，打包的时候压缩
//webpack默认的压缩配置，在IE8下面会出错
if (ENV.__PRERELEASE__ || ENV.__TEST__) {
    config.plugins.push(
        new webpack.optimize.UglifyJsPlugin({
            beautify: false,
            sourceMap: false,
            mangle: {
                screw_ie8: false,
                keep_fnames: false
            },
            compress: {
                sequences: 10,
                drop_debugger: true,
                conditionals: true,
                booleans: true,
                dead_code: true,
                unused: true,
                if_return:true,
                join_vars:true,
                warnings: false,
                screw_ie8: false
            },
            output: {
                screw_ie8: false
            },
            comments: false,
        })
    )
}

//其他文件复制
const copyFiles=[
    {
        from: path.resolve(__dirname, './src/vendors'),
        to: path.resolve(__dirname, `./${DIST}/vendors`),
    }
];
if(ENV.__TEST__){   //测试环境使用，主要测试IE
    copyFiles.push({
        from: path.resolve(__dirname, './src/server.js'),
        to: path.resolve(__dirname, `./${DIST}`),
    });
}
config.plugins.push(new CopyWebpackPlugin(copyFiles));

/**
 * 其他页面模板，根据入口文件生成html
 * 多页面自动化处理
 */
const views = Object.keys(fileResolve('./src/page/**.js'));
//html文件的描述信息
const descJSON = require('./src/json/html-desc.json');
views.forEach((filename) => {

    //获取html文件的描述信息
    const defaultDesc = {
        title:'Web Demo',
        id:filename,
        filename:filename,
        metas:''
    }
    const desc =Object.assign({},defaultDesc,descJSON[filename]);

    config.plugins.push(
        new HtmlWebpackPlugin({
            title: desc.title,
            id:desc.id,
            metas:desc.metas,
            filename: `./views/${desc.filename}.html`, //生成的html存放路径，相对于path
            template: viewTemplate, //html模板文件
            minify: { //压缩HTML文件
                minimize: false, //压缩
                removeComments: false, //移除HTML中的注释
                collapseWhitespace: false //删除空白符与换行符
            },
            favicon: favicon || '',
            chunks: [commonChunkName, filename],
            hash: false
        })
    );
});

//给组件取别名，方便require/import调用
//在alias.json中配置
const aliasJSONMap = require('./src/json/alias.json');
Object.keys(aliasJSONMap).forEach((k, i) => {
    config.resolve.alias[k] = path.join(__dirname, aliasJSONMap[k]);
});

//添加额外的引用比如dll生产的js font-awesome等静态资源
const assetsJSONArray = require('./src/json/assets.json');
const assetsArray = [];
assetsJSONArray.forEach((assetsMap, index) => {
    assetsArray.push({
        filepath: require.resolve(assetsMap.filepath),
        includeSourcemap: false,
        typeOfAsset: assetsMap.typeOfAsset || 'js',
        publicPath: publicPath + assetsMap.publicPath,
        outputPath: assetsMap.outputPath
    });
});
config.plugins.push(new AddAssetHtmlPlugin(assetsArray));

module.exports = config
